#include "Hud.h"
#include "PhysicsLogic.h"
#include <iostream>
#include "freetype/freetype.h"

GLdouble Hud::prevProjectionMatrix[];
GLdouble Hud::prevModelviewMatrix[];
FTTextureFont Hud::font("res/fonts/arialbd.ttf");
FTBitmapFont Hud::bitmapFont("res/fonts/arialbd.ttf");

void Hud::Init() {

	font.FaceSize(16+3);
	font.CharMap(ft_encoding_unicode);
	font.UseDisplayList(true);

	bitmapFont.FaceSize(16+3);
	bitmapFont.CharMap(ft_encoding_unicode);
	bitmapFont.UseDisplayList(true);
}

void Hud::Begin() {
	//save previous matrices
	glGetDoublev(GL_PROJECTION_MATRIX, prevProjectionMatrix);
	glGetDoublev(GL_MODELVIEW_MATRIX, prevModelviewMatrix);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, Renderer::GetActiveScreenW(), Renderer::GetActiveScreenH(), 0, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glDisable(GL_DEPTH_TEST);
	glDepthMask(GL_FALSE);

	glDisable(GL_LIGHTING);
}

void Hud::End() {
	glEnable(GL_LIGHTING);

	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);

	//load previous matrices
	glMatrixMode(GL_PROJECTION);
	glLoadMatrixd(prevProjectionMatrix);
	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixd(prevModelviewMatrix);
}

unsigned int Hud::CheckHit(int x, int y) {
	GLuint buff[64] = {0};
	GLint view[4];

	glSelectBuffer(64, buff);

	glGetIntegerv(GL_VIEWPORT, view);
	glRenderMode(GL_SELECT);
	glInitNames();
	glPushName(0);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
		glLoadIdentity();

		int screenHeight = Renderer::GetActiveScreenH();
		int screenWidth = Renderer::GetActiveScreenW();

		gluPickMatrix(x, screenHeight - y, 1.0, 1.0, view);
		glOrtho(0, screenWidth, screenHeight, 0, -1, 1);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		PhysicsLogic::DrawHud(GL_SELECT);

		//glutSwapBuffers();

		//glMatrixMode(GL_PROJECTION);
		//glLoadIdentity();
	glPopMatrix();

	GLint hits = glRenderMode(GL_RENDER);

	GLuint hitName = 0;
	//one hit
	if(hits == 1)
	{
		hitName = buff[3];
	}
	//more than one hit -> choose nearest
	if(hits > 1)
	{
		GLuint nearestHit = 256;
		for (int i = 0; i < hits; i++)
		{
			GLuint depth = buff[i * 4 + 1];
			if(depth < nearestHit)
			{
				nearestHit = depth;
				hitName = buff[i * 4 + 3];
			}
		}
	}

	//glMatrixMode(GL_MODELVIEW);

	return hitName;
}

float Hud::GetTextLineHeight(int lineNumber, bool fromTop) {
	float result = 0.0f;
	const float m = GetTextMargin();
	const float h = GetCharHeight();
	if(fromTop) {
		result = m + (h + m)*lineNumber;
	} else {
		result = Renderer::GetActiveScreenH() - (m + (h + m)*lineNumber);
	}
	return result;
}

void Hud::TextBase(const char* text, float x, float y) {
	if(text && strlen(text)) {
		//glRasterPos2f(x, y); //only bitmap/pixmap
		glPushMatrix();
		glTranslatef(x, y, 0.0);
		glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //because texturefonts use other coords
		glRotatef(180.0f, 0.0f, 0.0f, 1.0f); //
		font.Render(text);
		glPopMatrix();
	}
}

void Hud::TextBaseBitmap(const char* text, float x, float y) {
	if(text && strlen(text)) {
		glRasterPos2f(x, y);
		bitmapFont.Render(text);
	}
}

void Hud::TextFg(const char* text, float x, float y) {
	TextBase(text, x, y);
}

void Hud::TextBg(const char* text, float x, float y) {
	TextBase(text, x, y+1);
	TextBase(text, x, y-1);
	TextBase(text, x+1, y);
	TextBase(text, x-1, y);
}

void Hud::Text(const char* text, float x, float y, bool centered, const SurfaceRenderingData& fg, const SurfaceRenderingData& bg) {
	NxVec3 upperRight;
	NxVec3 lowerLeft;
	font.BBox(text, upperRight.x, upperRight.y, upperRight.z, lowerLeft.x, lowerLeft.y, lowerLeft.z);
	const NxVec3 fontSize(lowerLeft - upperRight);

	float tx;
	float ty;
	if(centered) {
		tx = x - fontSize.x * 0.5f;
		ty = y + fontSize.y * 0.5f;
	} else {
		tx = x;
		ty = y;
	}
	
	glEnable(GL_TEXTURE_2D);

	Renderer::SetMaterial(bg);
	TextBg(text, tx, ty);
	Renderer::SetMaterial(fg);
	TextFg(text, tx, ty);

	glDisable(GL_TEXTURE_2D);
}

void Hud::Arrow(float size) {
	glBegin(GL_TRIANGLES);

	glNormal3f(0.0f, 0.0f, 1.0f);
	glVertex2f(0, -size);
	glVertex2f(-size/2, size);
	glVertex2f(size/2, size);

	glEnd();
}

void Hud::Rect(float x1, float y1, float x2, float y2) {
	glBegin(GL_QUADS);

	glNormal3f(0.0f, 0.0f, 1.0f);
	glTexCoord2f(1, 0);
	glVertex2f(x2, y1);
	glTexCoord2f(0, 0);
	glVertex2f(x1, y1);
	glTexCoord2f(0, 1);
	glVertex2f(x1, y2);
	glTexCoord2f(1, 1);
	glVertex2f(x2, y2);

	glEnd();
}

void Hud::Line(float x1, float y1, float x2, float y2) {
	glBegin(GL_LINES);

	glVertex2f(x1, y1);
	glVertex2f(x2, y2);

	glEnd();
}

void Hud::Image(DevilTexture *texture, float x, float y) {
	int texWidth = texture->GetWidth();
	int texHeight = texture->GetHeight();
	texture->Use();
	glBegin(GL_QUADS);
	glNormal3f(0.0f, 0.0f, -1.0f);
	glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y + texHeight);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + texWidth, y + texHeight);
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + texWidth, y);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y);
	glEnd();
}
